Correctly set enter/leave events as detail=nonlinear
authorAlexander Larsson <alexl@redhat.com>
Thu, 9 Jul 2009 14:48:22 +0000 (16:48 +0200)
committerAlexander Larsson <alexl@redhat.com>
Thu, 9 Jul 2009 15:06:46 +0000 (17:06 +0200)
If we get a nonlinear enter/leave notify on the toplevel we need
to set nonlinear in all the events we send, even if the in-toplevel
tree is linear.

This fixes combobox menus popping down immediately when you click
(not hold). (bug #587559)

gdk/gdkdisplay.c
gdk/gdkinternals.h
gdk/gdkwindow.c
gtk/gtkmenu.c

index d599ba73382fc37ac6afdb7817bd842ea3141b59..399d1939992f8b698ee55bbc44e31c49ed224fcc 100644 (file)
@@ -856,26 +856,26 @@ synthesize_crossing_events (GdkDisplay *display,
       gdk_window_get_pointer (dest_toplevel,
                              &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-                                     src_window,
-                                     dest_window,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+                                      src_window,
+                                      dest_window,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
     }
   else if (dest_toplevel == NULL)
     {
       gdk_window_get_pointer (src_toplevel,
                              &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-                                     src_window,
-                                     NULL,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+                                      src_window,
+                                      NULL,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
     }
   else
     {
@@ -883,23 +883,23 @@ synthesize_crossing_events (GdkDisplay *display,
       gdk_window_get_pointer (src_toplevel,
                              &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-                                     src_window,
-                                     NULL,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+                                      src_window,
+                                      NULL,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
       gdk_window_get_pointer (dest_toplevel,
                              &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-                                     NULL,
-                                     dest_window,
-                                     crossing_mode,
-                                     x, y, state,
-                                     time,
-                                     NULL,
-                                     serial);
+                                      NULL,
+                                      dest_window,
+                                      crossing_mode,
+                                      x, y, state,
+                                      time,
+                                      NULL,
+                                      serial, FALSE);
     }
 }
 
index c9843860b13442eb6071c46f3a5b770284e834c3..6d1a4d061329fe4b118dbc5c1c4baac95ea6dd6b 100644 (file)
@@ -628,15 +628,16 @@ GdkEvent * _gdk_make_event (GdkWindow    *window,
                            gboolean      before_event);
 
 void _gdk_synthesize_crossing_events (GdkDisplay                 *display,
-                                    GdkWindow                  *src,
-                                    GdkWindow                  *dest,
-                                    GdkCrossingMode             mode,
-                                    gint                        toplevel_x,
-                                    gint                        toplevel_y,
-                                    GdkModifierType             mask,
-                                    guint32                     time_,
-                                    GdkEvent                   *event_in_queue,
-                                    gulong                      serial);
+                                     GdkWindow                  *src,
+                                     GdkWindow                  *dest,
+                                     GdkCrossingMode             mode,
+                                     gint                        toplevel_x,
+                                     gint                        toplevel_y,
+                                     GdkModifierType             mask,
+                                     guint32                     time_,
+                                     GdkEvent                   *event_in_queue,
+                                     gulong                      serial,
+                                     gboolean                    non_linear);
 void _gdk_display_set_window_under_pointer (GdkDisplay *display,
                                            GdkWindow *window);
 
index bd253c716daa5ffb546aa76276e99407a12abf34..dd7df890f9e1dfc2f9d8a2a0ef3acc75e48fbac2 100644 (file)
@@ -8494,20 +8494,20 @@ send_crossing_event (GdkDisplay                 *display,
  */
 void
 _gdk_synthesize_crossing_events (GdkDisplay                 *display,
-                               GdkWindow                  *src,
-                               GdkWindow                  *dest,
-                               GdkCrossingMode             mode,
-                               gint                        toplevel_x,
-                               gint                        toplevel_y,
-                               GdkModifierType             mask,
-                               guint32                     time_,
-                               GdkEvent                   *event_in_queue,
-                               gulong                      serial)
+                                GdkWindow                  *src,
+                                GdkWindow                  *dest,
+                                GdkCrossingMode             mode,
+                                gint                        toplevel_x,
+                                gint                        toplevel_y,
+                                GdkModifierType             mask,
+                                guint32                     time_,
+                                GdkEvent                   *event_in_queue,
+                                gulong                      serial,
+                                gboolean                    non_linear)
 {
   GdkWindowObject *c;
   GdkWindowObject *win, *last, *next;
   GList *path, *list;
-  gboolean non_linear;
   GdkWindowObject *a;
   GdkWindowObject *b;
   GdkWindowObject *toplevel;
@@ -8522,7 +8522,7 @@ _gdk_synthesize_crossing_events (GdkDisplay                 *display,
 
   c = find_common_ancestor (a, b);
 
-  non_linear = (c != a) && (c != b);
+  non_linear |= (c != a) && (c != b);
 
   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
     {
@@ -8821,15 +8821,16 @@ do_synthesize_crossing_event (gpointer data)
          display->pointer_info.window_under_pointer)
        {
          _gdk_synthesize_crossing_events (display,
-                                         display->pointer_info.window_under_pointer,
-                                         new_window_under_pointer,
-                                         GDK_CROSSING_NORMAL,
-                                         display->pointer_info.toplevel_x,
-                                         display->pointer_info.toplevel_y,
-                                         display->pointer_info.state,
-                                         GDK_CURRENT_TIME,
-                                         NULL,
-                                         serial);
+                                          display->pointer_info.window_under_pointer,
+                                          new_window_under_pointer,
+                                          GDK_CROSSING_NORMAL,
+                                          display->pointer_info.toplevel_x,
+                                          display->pointer_info.toplevel_y,
+                                          display->pointer_info.state,
+                                          GDK_CURRENT_TIME,
+                                          NULL,
+                                          serial,
+                                          FALSE);
          _gdk_display_set_window_under_pointer (display, new_window_under_pointer);
        }
     }
@@ -8939,6 +8940,7 @@ proxy_pointer_event (GdkDisplay                 *display,
   guint state;
   gdouble toplevel_x, toplevel_y;
   guint32 time_;
+  gboolean non_linear;
 
   event_window = source_event->any.window;
   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
@@ -8948,6 +8950,12 @@ proxy_pointer_event (GdkDisplay                 *display,
                                                       toplevel_x, toplevel_y,
                                                       &toplevel_x, &toplevel_y);
 
+  non_linear = FALSE;
+  if ((source_event->type == GDK_LEAVE_NOTIFY ||
+       source_event->type == GDK_ENTER_NOTIFY) &&
+      (source_event->crossing.detail == GDK_NOTIFY_NONLINEAR ||
+       source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
+    non_linear = TRUE;
 
   /* If we get crossing events with subwindow unexpectedly being NULL
      that means there is a native subwindow that gdk doesn't know about.
@@ -8968,13 +8976,14 @@ proxy_pointer_event (GdkDisplay                 *display,
       /* Send leave events from window under pointer to event window
         that will get the subwindow == NULL window */
       _gdk_synthesize_crossing_events (display,
-                                     display->pointer_info.window_under_pointer,
-                                     event_window,
-                                     source_event->crossing.mode,
-                                     toplevel_x, toplevel_y,
-                                     state, time_,
-                                     source_event,
-                                     serial);
+                                      display->pointer_info.window_under_pointer,
+                                      event_window,
+                                      source_event->crossing.mode,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial,
+                                      non_linear);
 
       /* Send subwindow == NULL event */
       send_crossing_event (display,
@@ -9020,13 +9029,13 @@ proxy_pointer_event (GdkDisplay                 *display,
 
       /* Send enter events from event window to pointer_window */
       _gdk_synthesize_crossing_events (display,
-                                     event_window,
-                                     pointer_window,
-                                     source_event->crossing.mode,
-                                     toplevel_x, toplevel_y,
-                                     state, time_,
-                                     source_event,
-                                     serial);
+                                      event_window,
+                                      pointer_window,
+                                      source_event->crossing.mode,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial, non_linear);
       _gdk_display_set_window_under_pointer (display, pointer_window);
       return TRUE;
     }
@@ -9038,13 +9047,13 @@ proxy_pointer_event (GdkDisplay                 *display,
 
       /* Different than last time, send crossing events */
       _gdk_synthesize_crossing_events (display,
-                                     display->pointer_info.window_under_pointer,
-                                     pointer_window,
-                                     GDK_CROSSING_NORMAL,
-                                     toplevel_x, toplevel_y,
-                                     state, time_,
-                                     source_event,
-                                     serial);
+                                      display->pointer_info.window_under_pointer,
+                                      pointer_window,
+                                      GDK_CROSSING_NORMAL,
+                                      toplevel_x, toplevel_y,
+                                      state, time_,
+                                      source_event,
+                                      serial, non_linear);
       _gdk_display_set_window_under_pointer (display, pointer_window);
     }
   else if (source_event->type == GDK_MOTION_NOTIFY)
index 0fd5d3d4addf9b13891e0b9a8d13394e6dc4596e..98aeb212c913e4f30abf44054de50dc6f0eda370 100644 (file)
@@ -3792,6 +3792,47 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
     }
 }
 
+static char *mode[] = {
+  "GDK_CROSSING_NORMAL",
+  "GDK_CROSSING_GRAB",
+  "GDK_CROSSING_UNGRAB",
+  "GDK_CROSSING_GTK_GRAB",
+  "GDK_CROSSING_GTK_UNGRAB",
+  "GDK_CROSSING_STATE_CHANGED",
+  NULL
+};
+
+static char *detail[] = {
+  "GDK_NOTIFY_ANCESTOR",
+  "GDK_NOTIFY_VIRTUAL",
+  "GDK_NOTIFY_INFERIOR",
+  "GDK_NOTIFY_NONLINEAR",
+  "GDK_NOTIFY_NONLINEAR_VIRTUAL",
+  "GDK_NOTIFY_UNKNOWN",
+  NULL
+};
+
+char *
+get_window_name (GtkWidget *widget, GdkWindow *window)
+{
+  GtkMenu *menu;
+  gpointer w;
+  menu = GTK_MENU (widget);
+  
+  if (window == widget->window)
+    return "widget->window";
+
+  if (window == menu->view_window)
+    return "menu->view_window";
+  
+  if (window == menu->bin_window)
+    return "menu->bin_window";
+
+  gdk_window_get_user_data (window, &w);
+  
+  return g_type_name_from_instance (w);
+}
+
 static gboolean
 gtk_menu_enter_notify (GtkWidget        *widget,
                       GdkEventCrossing *event)
@@ -3804,6 +3845,10 @@ gtk_menu_enter_notify (GtkWidget        *widget,
       event->mode == GDK_CROSSING_STATE_CHANGED)
     return TRUE;
 
+  g_print ("menu ENTER notify for %s mode: %s, detail %s\n",
+          get_window_name (widget, event->window),
+          mode[event->mode], detail[event->detail]);
+  
   g_object_get (gtk_widget_get_settings (widget),
                 "gtk-touchscreen-mode", &touchscreen_mode,
                 NULL);
@@ -3846,6 +3891,7 @@ gtk_menu_enter_notify (GtkWidget        *widget,
                   * far enough away from the enter point. (see
                   * gtk_menu_motion_notify())
                   */
+                 g_print ("user-enter, not pop-under\n");
                  menu_shell->activate_time = 0;
                }
            }
@@ -3880,6 +3926,10 @@ gtk_menu_leave_notify (GtkWidget        *widget,
       event->mode == GDK_CROSSING_STATE_CHANGED)
     return TRUE;
 
+  g_print ("menu LEAVE notify for %s mode: %s, detail %s\n",
+          get_window_name (widget, event->window),
+          mode[event->mode], detail[event->detail]);
+
   menu = GTK_MENU (widget);
   menu_shell = GTK_MENU_SHELL (widget);